﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SSE657.BahMap.Common;
using System.IO;
using System.Security.Principal;

namespace SSE657.BahMap.DataAccess.Text
{
    public class BAHDataTextConnector : TextDataConnectorBase, IBAHDataConnector
    {
        public BAHDataTextConnector()
            : base()
        { }

        public IEnumerable<RateData> GetAreaRates(PayGrade grade, bool dependents)
        {
            List<RateData> rates = new List<RateData>();
            string filename = GetBAHFileName(dependents);
            StreamReader file = new StreamReader(Path.Combine(_rootDirectory + @"\BAH2012", filename));
            string line = file.ReadLine();
            while (line != null)
            {
                rates.Add(GetRateData(grade, dependents, line));
                line = file.ReadLine();
            }
            return rates;
        }

        private string GetBAHFileName(bool dependents)
        {
            string filename = "bah";
            filename += dependents ? "w12.txt" : "wo12.txt";
            return filename;
        }

        private RateData GetRateData(PayGrade grade, bool dependents, string fileLine)
        {
            //MHA,E1,E2,E3,...,W1,W2,...,O1E,O2E,...,O1,O2,...,O10
            int col = (int)grade + 1;
            string[] words = fileLine.Split(',');
            return new RateData()
            {
                Grade = grade,
                Rate = Double.Parse(words[col]),
                Dependents = dependents,
                Area = _mhaAreas[words[0]]
            };
        }

        public double GetRate(PayGrade grade, bool dependents, int zipcode)
        {
            foreach (string key in _mhaAreas.Keys)
            {
                if (_mhaAreas[key].ZIPs.Contains(zipcode))
                    return GetRate(grade, dependents, key);
            }

            throw new ArgumentException("zipcode not found");
        }

        public double GetRate(PayGrade grade, bool dependents, string MHA)
        {
            int col = (int)grade + 1;
            string filename = GetBAHFileName(dependents);
            StreamReader file = new StreamReader(Path.Combine(_rootDirectory + @"\BAH2012", filename));
            string line = file.ReadLine();
            while (line != null)
            {
                string[] words = line.Split(',');
                if (words[0] == MHA)
                    return double.Parse(words[col]);
                line = file.ReadLine();
            }

            throw new ArgumentException("MHA not found");
        }

        public IEnumerable<RateData> GetGradeRates(bool dependents, int zipcode)
        {
            foreach (string key in _mhaAreas.Keys)
            {
                if (_mhaAreas[key].ZIPs.Contains(zipcode))
                    return GetGradeRates(dependents, key);
            }

            throw new ArgumentException("zipcode not found");
        }

        public IEnumerable<RateData> GetGradeRates(bool dependents, string mha)
        {
            string filename = GetBAHFileName(dependents);
            StreamReader file = new StreamReader(Path.Combine(_rootDirectory + @"\BAH2012", filename));
            string line = file.ReadLine();
            while (line != null)
            {
                string[] words = line.Split(',');
                if (words[0] == mha)
                    return GetRateData(dependents, line);
                line = file.ReadLine();
            }

            throw new ArgumentException("MHA not found");
        }

        private IEnumerable<RateData> GetRateData(bool dependents, string fileLine)
        {
            List<RateData> rates = new List<RateData>();
            string[] words = fileLine.Split(',');
            foreach (PayGrade grade in Enum.GetValues(typeof(PayGrade)))
            {
                rates.Add(new RateData()
                {
                    Grade = grade,
                    Rate = double.Parse(words[(int)grade + 1]),
                    Dependents = dependents,
                    Area = _mhaAreas[words[0]]
                });
            }

            return rates;
        }

        public void GetRateAndRange(PayGrade grade, bool dependents, int zipcode, out double rate, out double min, out double max)
        {
            rate = max = double.MinValue;
            min = double.MaxValue;

            try
            {
                foreach (string key in _mhaAreas.Keys)
                {
                    if (_mhaAreas[key].ZIPs.Contains(zipcode))
                        GetRateAndRange(grade, dependents, key, out rate, out min, out max);
                }

                if (rate == double.MinValue)
                    throw new ArgumentException("zipcode not found");
            }
            catch (ArgumentException)
            {
                throw new ArgumentException("zipcode not found");
            }
        }

        public void GetRateAndRange(PayGrade grade, bool dependents, string mha, out double rate, out double min, out double max)
        {
            int col = (int)grade + 1;
            min = double.MaxValue;
            max = double.MinValue;
            rate = double.MinValue;

            string filename = GetBAHFileName(dependents);
            StreamReader file = new StreamReader(Path.Combine(_rootDirectory + @"\BAH2012", filename));
            string line = file.ReadLine();
            while (line != null)
            {
                string[] words = line.Split(',');
                double thisRate = double.Parse(words[col]);
                min = thisRate < min ? thisRate : min;
                max = thisRate > max ? thisRate : max;
                if (words[0] == mha)
                {
                    rate = thisRate;
                }

                line = file.ReadLine();
            }

            if (rate == double.MinValue)
                throw new ArgumentException("MHA not found");
        }

        // this class is no longer useful, so do not implement the following methods

        public IEnumerable<RateData> GetRates(int zipcode)
        {
            List<RateData> results = new List<RateData>(GetGradeRates(false, zipcode));
            results.AddRange(GetGradeRates(true, zipcode));
            results.Sort(new RateDataOrderByPayGradeComparer());
            return results;
        }

        public IEnumerable<RateData> GetRates(string mha)
        {
            List<RateData> results = new List<RateData>(GetGradeRates(false, mha));
            results.AddRange(GetGradeRates(true, mha));
            results.Sort(new RateDataOrderByPayGradeComparer());
            return results;
        }
    }
}
